home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Moscow ML 1.42 / src / mosmllib / TextIO.sml < prev    next >
Encoding:
Text File  |  1997-08-18  |  10.4 KB  |  313 lines  |  [TEXT/R*ch]

  1. (* TextIO -- 1995-11-22, 1996-07-07; no positions etc. yet *)
  2.  
  3. type elem = Char.char
  4. type vector = string
  5. type pos = int
  6.  
  7. prim_val create_string_ : int -> string                 = 1 "create_string";
  8. prim_val nth_char_      : string -> int -> char         = 2 "get_nth_char";
  9. prim_val set_nth_char_  : string -> int -> char -> unit = 3 "set_nth_char";
  10. prim_val blit_string_   : string -> int -> string -> int -> int -> unit 
  11.                                                         = 5 "blit_string";
  12.  
  13. fun sub_string_ s start len =
  14.   let val res = create_string_ len
  15.   in blit_string_ s start res 0 len; res end
  16. ;
  17.  
  18. (* Caml Light "channels" *)
  19.  
  20. prim_type in_channel and out_channel;
  21.  
  22. prim_val open_descriptor_in : int -> in_channel = 1 "open_descriptor";
  23.         (* [open_descriptor_in fd] returns a buffered input channel
  24.            reading from the file descriptor [fd]. The file descriptor [fd]
  25.            must have been previously opened for reading, else the behavior is
  26.        undefined. *)
  27.  
  28. prim_val open_descriptor_out : int -> out_channel = 1 "open_descriptor";
  29.         (* [open_descriptor_out fd] returns a buffered output channel
  30.            writing to the file descriptor [fd]. The file descriptor [fd]
  31.            must have been previously opened for writing, else the behavior is
  32.        undefined. *)
  33.  
  34. prim_val input_char_ : in_channel -> char = 1 "input_char"
  35.         (* Read one character from the given input channel.
  36.            Raise [Size] if there are no more characters to read. *)
  37.  
  38. prim_val output_char_ : out_channel -> char -> unit = 2 "output_char";
  39.  
  40. prim_val caml_seek_in : in_channel -> int -> unit = 2 "seek_in"
  41.         (* [seek_in chan pos] sets the current reading position to [pos]
  42.            for channel [chan]. *)
  43.  
  44. prim_val caml_pos_in : in_channel -> int = 1 "pos_in";
  45.         (* Return the current reading position for the given channel. *)
  46.  
  47. prim_val caml_close_in : in_channel -> unit = 1 "close_in"
  48.         (* Close the given channel. Anything can happen if any of the
  49.            above functions is called on a closed channel. *)
  50.  
  51. type file_perm = int;
  52.  
  53. datatype open_flag =
  54.     O_RDONLY                       (* `open' read-only *)
  55.   | O_WRONLY                       (* `open' write-only *)
  56.   | O_RDWR                         (* `open' for reading and writing *)
  57.   | O_APPEND                       (* `open' for appending *)
  58.   | O_CREAT                        (* create the file if nonexistent *)
  59.   | O_TRUNC                        (* truncate the file to 0 if it exists *)
  60.   | O_EXCL                         (* fails if the file exists *)
  61.   | O_BINARY                       (* `open' in binary mode *)
  62.   | O_TEXT                         (* `open' in text mode *)
  63. ;
  64.  
  65. prim_val sys_open :
  66.   string -> open_flag list -> file_perm -> int = 3 "sys_open"
  67.         (* Open a file. The second argument is the opening mode.
  68.            The third argument is the permissions to use if the file
  69.            must be created. The result is a file descriptor opened on the
  70.            file. *)
  71. prim_val sys_close :
  72.   int -> unit = 1 "sys_close"
  73.         (* Close a file descriptor. *)
  74.  
  75. val caml_std_in  = open_descriptor_in 0
  76. and caml_std_out = open_descriptor_out 1
  77. and caml_std_err = open_descriptor_out 2
  78. ;
  79.  
  80. prim_val fast_input :
  81.   in_channel -> string -> int -> int -> int = 4 "input";
  82. prim_val fast_output :
  83.   out_channel -> string -> int -> int -> unit = 4 "output";
  84.  
  85. fun caml_open_in_gen mode rights filename =
  86.   open_descriptor_in (sys_open filename mode rights)
  87. ;
  88.  
  89. val caml_open_in = caml_open_in_gen [O_RDONLY, O_TEXT] 0
  90. and caml_open_in_bin = caml_open_in_gen [O_RDONLY, O_BINARY] 0
  91. ;
  92.  
  93. fun open_out_gen mode rights filename =
  94.   open_descriptor_out(sys_open filename mode rights)
  95. ;
  96.  
  97. prim_val s_irall : file_perm = 0 "s_irall";
  98. prim_val s_iwall : file_perm = 0 "s_iwall";
  99.  
  100. val caml_open_out =
  101.   open_out_gen [O_WRONLY, O_TRUNC, O_CREAT, O_TEXT] (s_irall + s_iwall)
  102. and caml_open_out_bin =
  103.   open_out_gen [O_WRONLY, O_TRUNC, O_CREAT, O_BINARY] (s_irall + s_iwall)
  104. ;
  105.  
  106. prim_val caml_flush : out_channel -> unit = 1 "flush"
  107.         (* Flush the buffer associated with the given output channel,
  108.            performing all pending writes on that channel.
  109.            Interactive programs must be careful about flushing [std_out]
  110.            at the right times. *)
  111.  
  112. fun caml_output_string channel s =
  113.     fast_output channel s 0 (size s);
  114.  
  115. prim_val caml_close_out : out_channel -> unit = 1 "close_out"
  116.         (* Close the given channel, flushing all buffered write operations.
  117.        The behavior is unspecified if any of the above functions is
  118.        called on a closed channel. *)
  119.  
  120. fun try_input_char_ ic =
  121.   SOME (input_char_ ic)
  122.   handle Size => NONE;
  123.  
  124. (* Moscow ML imperative Text I/O *)
  125.  
  126. type instream  = { closed: bool, ic: in_channel,  name : string} ref;
  127. type outstream = { closed: bool, oc: out_channel, name : string} ref;
  128.  
  129. val stdIn  : instream  = 
  130.     ref { closed=false, ic=caml_std_in,  name = "<stdIn>"  }
  131. and stdOut : outstream = 
  132.     ref { closed=false, oc=caml_std_out, name = "<stdOut>" }
  133. and stdErr : outstream = 
  134.     ref { closed=false, oc=caml_std_err, name = "<stdErr>" };
  135.  
  136. fun raiseIo fcn nam exn = 
  137.     raise Io {function = fcn, name = nam, cause = exn};
  138.  
  139. fun raiseClosed fcn nam = 
  140.     raiseIo fcn nam (Fail "Stream is closed");
  141.  
  142. fun openIn s =
  143.   ref {closed=false, ic=caml_open_in s, name = s}
  144.   handle exn as SysErr _ => raiseIo "openIn" s exn;
  145.  
  146. fun closeIn (is as ref {closed, ic, name}) =
  147.   if closed then () 
  148.   else (caml_close_in ic;
  149.     is := { closed=true, ic=ic, name=name });
  150.  
  151. fun input1 (is as ref {closed, ic, name}) =
  152.     if closed then NONE 
  153.     else 
  154.     SOME (input_char_ ic)
  155.     handle Size => NONE;
  156.  
  157. fun input (is as ref {closed, ic, name}) =
  158.     if closed then "" 
  159.     else let val buff = create_string_ 60 
  160.      in case fast_input ic buff 0 60 of
  161.          0 => ""
  162.        | m => sub_string_ buff 0 m
  163.      end;
  164.  
  165. fun inputN (is as ref {closed, ic, name}, n) =
  166.     if n < 0 orelse n > String.maxSize then raise Size
  167.     else if closed then "" 
  168.     else let val buff = create_string_ n
  169.          fun loop k =
  170.          if k = n then buff
  171.          else
  172.              case fast_input ic buff k (n-k) of
  173.              0 => sub_string_ buff 0 k
  174.                | m => loop (k+m)
  175.      in loop 0 end;
  176.  
  177. fun inputAll (is as ref {closed, ic, name}) =
  178.   if closed then "" else
  179.   let val max = ref 127
  180.       val tmp = ref (create_string_ (!max))
  181.       fun realloc () =
  182.       let val newmax = if !max = String.maxSize then raise Size
  183.                else if 2 * !max >= String.maxSize then String.maxSize
  184.                else 2 * !max
  185.           val newtmp = create_string_ newmax
  186.       in 
  187.           blit_string_ (!tmp) 0 newtmp 0 (!max);
  188.           max := newmax;
  189.           tmp := newtmp
  190.       end
  191.       (* Don't read more than runtime/io.IO_BUFFER_SIZE characters:  *)
  192.       fun chunksize sz = if sz > 4096 then 4096 else sz
  193.       fun h len =
  194.       case fast_input ic (!tmp) len (chunksize (!max - len)) of
  195.           0 => sub_string_ (!tmp) 0 len
  196.         | m => (if !max - (len + m) < 127 then realloc () else ();
  197.             h (len + m));
  198.   in h 0 end;
  199.  
  200. type cs = int (* character source state *)
  201.  
  202. fun scanStream scan  (instrm as ref {closed, ic, name}) =
  203.     let prim_eqtype array_
  204.     prim_val array_  : int -> array_                 = 1 "create_string";
  205.     prim_val sub_    : array_ -> int -> char         = 2 "get_nth_char";
  206.     prim_val update_ : array_ -> int -> char -> unit = 3 "set_nth_char";
  207.  
  208.         val buf  = array_ 512        (* characters recently read     *)
  209.     val read = ref 0        (* number of characters read    *)
  210.     fun getc charno =
  211.         if charno < !read then        (* already read         *)
  212.         if charno >= !read - 512 then    (* still in buffer      *)
  213.             SOME(sub_ buf (charno mod 512), charno+1)
  214.         else                (* no longer in buffer  *)
  215.             raise Fail "scanStream: backtracking too far"
  216.         else            (* charno = !read; read a new character *)
  217.         if closed then NONE
  218.         else (let val c = input_char_ ic
  219.               in (update_ buf (charno mod 512) c;
  220.               read := !read + 1;
  221.               SOME(c, charno+1))
  222.               end handle Size => NONE)
  223.     in case scan getc 0 of
  224.         NONE         => NONE
  225.       | SOME(res, _) => SOME res
  226.     end;
  227.  
  228. fun inputNoBlock (is : instream) : vector option =
  229.     raise Fail "not implemented";
  230.  
  231. fun lookahead (is as ref {closed, ic, name}) =
  232.   if closed then NONE else
  233.   let val pos = caml_pos_in ic in
  234.       case try_input_char_ ic of
  235.       NONE            => NONE
  236.     | res as (SOME c) => (caml_seek_in ic pos; res)
  237.   end;
  238.  
  239. fun endOfStream is = (lookahead is = NONE);
  240.  
  241. fun openAppend (s : string) : outstream =
  242.   ref { closed=false,
  243.         oc=open_out_gen [O_WRONLY, O_APPEND, O_CREAT, O_TEXT]
  244.                         (s_irall + s_iwall) s,
  245.     name=s}
  246.   handle exn as SysErr _ => raiseIo "openAppend" s exn;
  247.  
  248. fun output (os as ref {closed, oc, name}, s) =
  249.     if closed then
  250.     raiseClosed "output" name
  251.     else
  252.     (caml_output_string oc s;
  253.      if os = stdErr then caml_flush oc else ());
  254.  
  255. fun outputSubstr (os as ref {closed, oc, name}, sus : substring) =
  256.     let prim_val substrToTrip : substring -> string * int * int = 1 "identity"
  257.         val (s, i, n) = substrToTrip sus
  258.     in if closed then
  259.       raiseClosed "outputSubstr" name
  260.        else
  261.        (fast_output oc s i n;
  262.         if os = stdErr then caml_flush oc else ())
  263.     end;
  264.  
  265. fun output1 (os as ref {closed, oc, name}, c) =
  266.     if closed then
  267.     raiseClosed "output1" name
  268.     else
  269.     (output_char_ oc c;
  270.      if os = stdErr then caml_flush oc else ());
  271.  
  272. fun inputLine (is as ref {closed, ic, name}) =
  273.   if closed then "" else
  274.   let val max = ref 127
  275.       val tmp = ref (create_string_ (!max))
  276.       fun realloc () =
  277.       let val newmax = if !max = String.maxSize then raise Size
  278.                else if 2 * !max >= String.maxSize then String.maxSize
  279.                else 2 * !max
  280.           val newtmp = create_string_ newmax
  281.       in 
  282.           blit_string_ (!tmp) 0 newtmp 0 (!max);
  283.           max := newmax;
  284.           tmp := newtmp
  285.       end
  286.       fun h len =
  287.       (if len >= !max then realloc () else ();
  288.        case try_input_char_ ic of
  289.            NONE   => (set_nth_char_ (!tmp) len #"\n"; 
  290.               sub_string_ (!tmp) 0 (len+1))
  291.          | SOME c => (set_nth_char_ (!tmp) len c;
  292.               if c = #"\n" then sub_string_ (!tmp) 0 (len+1) 
  293.                            else h (len+1)))
  294.   in if endOfStream is then "" else h 0 end;
  295.  
  296. fun openOut (s : string) : outstream =
  297.     ref {closed=false, oc=caml_open_out s, name=s}
  298.     handle exn as SysErr _ => raiseIo "openOut" s exn;
  299.  
  300. fun closeOut (os as ref {closed, oc, name}) =
  301.     if closed then () 
  302.     else (caml_close_out oc; 
  303.       os := {closed = true, oc=oc, name=name}; 
  304.       ());
  305.  
  306. fun flushOut (os as ref {closed, oc, name}) =
  307.   if closed then
  308.       raiseClosed "flushOut" name
  309.   else
  310.       caml_flush oc;
  311.  
  312. fun print s = (output(stdOut, s); flushOut stdOut);
  313.